package automaton.efsm;
import java.util.ArrayList;

import automaton.AbstractAutomaton;
import automaton.AbstractAutomaton.Transition;
/**
 * 
 * @author Daniil Chivilikhin
 *
 */
public class DefiniteEFSM extends AbstractEFSM {
	public DefiniteEFSM.Transition[][] transitions;
	private int numberOfStates;
	private int initialState;
	private int stepCnt;
	private int numberOfExternalInfluences;

	public DefiniteEFSM(int numberOfStates, int numberOfExternalInfluences,
			DefiniteEFSM.Transition[][] tr) {
		this.numberOfStates = numberOfStates;
		this.numberOfExternalInfluences = numberOfExternalInfluences;
		this.transitions = tr;
	}

	public DefiniteEFSM(DefiniteEFSM other) {
		numberOfExternalInfluences = other.numberOfExternalInfluences;
		numberOfStates = other.numberOfStates;
		transitions = new DefiniteEFSM.Transition[numberOfStates][numberOfExternalInfluences];
		for (int i = 0; i < numberOfStates; i++) {
			for (int j = 0; j < numberOfExternalInfluences; j++) {
				transitions[i][j] = new DefiniteEFSM.Transition(other.transitions[i][j]);
			}
		}
	}

//	public DFA(String filename) {
//		Scanner in = null;
//
//		try {
//			in = new Scanner(new File(filename));
//		} catch (FileNotFoundException e) {
//			e.printStackTrace();
//		}
//
//		numberOfStates = in.nextInt();
//		numberOfExternalInfluences = in.nextInt();
//		transitions = new DFA.Transition[numberOfStates][numberOfExternalInfluences];
//		initialState = 0;
//		stepCnt = 0;
//		in.nextLine();
//		
//		for (int i = 0; i < numberOfStates; i++) {
//			for (int j = 0; j < numberOfExternalInfluences; j++) {
//				ArrayList<String> empty = new ArrayList<String>();
//				empty.add("");
//				transitions[i][j] = new DFA.Transition(i, -1, empty);
//			}
//		}
//		
//		while (in.hasNext()) {
//			String s = in.nextLine();
//			String[] list = s.split(" - > ");
//			for (int k = 0; k < list.length; k++) {
//				list[k] = list[k].replace("(", "");
//				list[k] = list[k].replace(")", "");
//				list[k] = list[k].replace(",", "");
//			}
//
//			String[] startAndEvent = list[0].split(" ");
//			String[] endAndAction = list[1].split(" ");
//
//			int startState = Integer.parseInt(startAndEvent[0]);
//			int endState = Integer.parseInt(endAndAction[0]);
//			int event = Integer.parseInt(startAndEvent[1]);
//			String action = endAndAction[1];
//
//			transitions[startState][event] = new DFA.Transition(startState, endState,
//					action);
//		}
//	}
	
	public void setStepCnt(int stepCnt) {
		this.stepCnt = stepCnt;
	}

	public int getStepCnt() {
		return stepCnt;
	}

	public int getNumberOfTransitions() {
		int result = 0;
		for (int i = 0; i < numberOfStates; i++) {
			for (int j = 0; j < numberOfExternalInfluences; j++) {
				if (transitions[i][j].getEndState() != -1) {
					result++;
				}
			}
		}
		return result;
	}

	
	@Override
	public int getInitialState() {
		return initialState;
	}

	@Override
	public int getNumberOfStates() {
		return numberOfStates;
	}

	public DefiniteEFSM.Transition getTransition(int state, int action) {
		return transitions[state][action];
	}

	@Override
	public void setInitialState(int state) {
		this.initialState = state;
	}

	public String toString() {
		String a = numberOfStates + " " + numberOfExternalInfluences + "\n";
		for (int i = 0; i < numberOfStates; i++) {
			for (int j = 0; j < numberOfExternalInfluences; j++) {
				if (transitions[i][j].getEndState() == -1) {
					continue;
				}
				a += "(" + i + ", " + j + ") - > " + transitions[i][j] + "\n";
			}
		}
		return a;
	}

	public int getNumberOfExternalInfluences() {
		return numberOfExternalInfluences;
	}

	public static class Transition implements AbstractAutomaton.Transition {
		private int startState;
		private int endState;
		private ArrayList<String> actions;

		public Transition(int startState, int endState, ArrayList<String> actions) {
			this.startState = startState;
			this.endState = endState;
			this.actions = (ArrayList<String>) actions.clone();
		}

		public Transition(NondefiniteEFSM.Transition t) {
			startState = t.getStartState();
			endState = t.getEndState();
			actions = (ArrayList<String>) t.getActions().clone();
		}

		public Transition(Transition other) {
			endState = other.endState;
			actions = (ArrayList<String>) other.actions.clone();
		}

		public NondefiniteEFSM.Transition toNFATransition() {
			return new NondefiniteEFSM.Transition(startState, endState, actions, -1);
		}

		public boolean equals(DefiniteEFSM.Transition other) {
			boolean first = this.startState == other.startState &&
					this.endState == other.endState;
			if (!first || actions.size() != other.actions.size()) {
				return false;
			}
			
			for (int i = 0; i < actions.size(); i++) {
				if (!actions.get(i).equals(other.actions.get(i))) {
					return false;
				}
			}
			return true;
		}

		public ArrayList<String> getActions() {
			return (ArrayList<String>) actions.clone();
		}

		public void setActions(ArrayList<String> actions) {
			this.actions = (ArrayList<String>) actions.clone();
		}

		@Override
		public int getEndState() {
			return endState;
		}

		@Override
		public automaton.AbstractAutomaton.Transition setEndState(int state) {
			return new Transition(startState, state, actions);
		}

		public String toString() {
			String actionsToPrint = "";
			for (int i = 0; i < actions.size() - 1; i++) {
				if (!actions.get(i).equals("zn")) {
					actionsToPrint += actions.get(i);
				}
				actionsToPrint += ",";
			}
			if (!actions.get(actions.size() - 1).equals("zn")) {
				actionsToPrint += actions.get(actions.size() - 1);
			}
			return "(" + endState + ", " + actionsToPrint + ")";
		}

		@Override
		public int getStartState() {
			return startState;
		}
	}
}
